home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / prog / pas_all.zip / TI607.ASC < prev    next >
Text File  |  1992-05-13  |  19KB  |  661 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.   PRODUCT  :  Turbo Pascal                           NUMBER  :  607
  9.   VERSION  :  1.0
  10.        OS  :  Windows
  11.      DATE  :  May 13, 1992                            PAGE  :  1/10
  12.  
  13.     TITLE  :  How to Print in Windows
  14.  
  15.  
  16.  
  17.  
  18.   Printing in Windows is achieved with a device control associated
  19.   with the printing device described in the WIN.INI.  Before you
  20.   start printing in your program, you will need to create a device
  21.   control associated with your printer.
  22.  
  23.   To do this, you will call the function GetProfileString as
  24.   follows.
  25.  
  26.               GetMem(Info, 80);
  27.               GetProfileString('windows','device',',,', Info, 80);
  28.  
  29.   Where Info is defined to be of type PChar.  The resulting ASCIIZ
  30.   string will be placed in Info.  Unfortunately, CreateDC requires
  31.   three parameters, one for the driver, the printer type, and the
  32.   port.  If GetProfileString is successful, Info contains all the
  33.   information required by CreateDC but contained in one string
  34.   separated by semi-colons.  These items must be parsed out of the
  35.   string Info before CreateDC can be called.  The following
  36.   function is helpful in this task.
  37.  
  38.         function GetItem(var S:PChar): PChar;
  39.         var
  40.           P: PChar;
  41.           I: Integer;
  42.         begin
  43.           i:=0;
  44.           while (S[I]<>',') and (S[I]<>#0) do
  45.              inc(I);
  46.           S[I]:=#0;
  47.           GetItem:=S;
  48.  
  49.           if S[0]<>#0 then S:=   ;
  50.         end;
  51.  
  52.   The function GetItem does not copy the strings but rather turns
  53.   the larger string into a structure containing smaller component
  54.   strings.  Now separating the driver, printer type, and port
  55.   information is fairly straight forward.  Assuming that the PChar
  56.   variables Driver, PrinterType, Port and TInfo have been
  57.   predeclared, you would use the following assignments.
  58.  
  59.  
  60.  
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.  
  74.   PRODUCT  :  Turbo Pascal                           NUMBER  :  607
  75.   VERSION  :  1.0
  76.        OS  :  Windows
  77.      DATE  :  May 13, 1992                            PAGE  :  2/10
  78.  
  79.     TITLE  :  How to Print in Windows
  80.  
  81.  
  82.  
  83.  
  84.         TInfo:=Info;
  85.         PrinterType:=GetItem(Info);
  86.         Driver:=GetItem(Info);
  87.         Port:=GetItem(Info);
  88.  
  89.   The variable TInfo is necessary for a subsequent FreeMem call to
  90.   free up the memory originally allocated for Info.
  91.  
  92.   At last, you may now call CreateDC with the appropriate
  93.   parameters (assuming DC was previously declared to be of type
  94.   HDC).
  95.  
  96.         DC:=CreateDC(Driver, PrinterType, Port, Nil);
  97.  
  98.   If for some reason CreateDC is not successful, it will return a
  99.   value of zero.
  100.  
  101.   Now you are ready to start using the Escape function.  Escape is
  102.   a very special function as it allows access to device
  103.   capabilities that are not supported by the Windows GDI.  The
  104.   second parameter to Escape represents the particular escape
  105.   function to be used.  Two fundamental escape functions always
  106.   used when printing in Windows are STARTDOC and ENDDOC. These
  107.   functions do any setup and shutdown required by the printer.
  108.   Another important escape function is NEWFRAME.  NEWFRAME forces a
  109.   buffer flush and causes either a form feed operation or a page
  110.   eject operation depending upon the type of printer used.
  111.  
  112.   To print some text, the following code illustrates the process
  113.   involved.
  114.  
  115.         procedure Print;
  116.         var
  117.           TInfo, Info: PChar;
  118.           Driver, PrinterType, Port: PChar;
  119.           DC: HDC;
  120.  
  121.         begin
  122.           GetMem(Info, 80);
  123.           GetProfileString('windows', 'device', ',,', Info, 80);
  124.  
  125.           TInfo:=Info;
  126.           Driver:=GetItem(Info);
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.   PRODUCT  :  Turbo Pascal                           NUMBER  :  607
  141.   VERSION  :  1.0
  142.        OS  :  Windows
  143.      DATE  :  May 13, 1992                            PAGE  :  3/10
  144.  
  145.     TITLE  :  How to Print in Windows
  146.  
  147.  
  148.  
  149.  
  150.           PrinterType:=GetItem(Info);
  151.           Port:=GetItem(Info);
  152.           DC:=CreateDC(PrinterType, Driver, Port, Nil);
  153.           FreeMem(TInfo, 80);
  154.  
  155.           if Escape(DC, STARTDOC, 8,
  156.                     StrNew('Doc Name'), nil)<0then
  157.           begin
  158.              MessageBox(Window, 'Printing can not be started', nil,
  159.                         mb_Ok or mb_IconStop);
  160.              exit;
  161.           end;
  162.  
  163.           if Escape(DC, NEWFRAME, 0, nil, nil)<0 then
  164.           begin
  165.              MessageBox(Window, 'Paper can not be advanced', nil,
  166.                mb_Ok or mb_IconStop);
  167.              exit;
  168.           end;
  169.  
  170.           TextOut(DC, 10, 10, 'This text is being printed', 26);
  171.  
  172.           if Escape(DC, NEWFRAME, 0, nil, nil)<0 then
  173.           begin
  174.              MessageBox(Window, 'Paper can not be advanced', nil,
  175.                mb_Ok or mb_IconStop);
  176.              exit;
  177.           end;
  178.  
  179.           if Escape(DC, ENDDOC, 0, nil, nil)<0 then
  180.           begin
  181.              MessageBox(Window, 'Error Printing', nil,
  182.                mb_Ok or mb_IconStop);
  183.              exit;
  184.           end;
  185.         end;
  186.  
  187.   Notice that if Escape fails that it returns a value less than
  188.   zero.  The actual errors are governed by the spooler constants
  189.   sp_Error, sp_OutOfDisk, sp_OutOfMemory, and sp_UserAbort.  It is
  190.   recommended that a NEWFRAME call precede and follow the intended
  191.   output to ensure that the printer is working with a fresh piece
  192.   of paper and flushes its buffer when printing ends.
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.   PRODUCT  :  Turbo Pascal                           NUMBER  :  607
  207.   VERSION  :  1.0
  208.        OS  :  Windows
  209.      DATE  :  May 13, 1992                            PAGE  :  4/10
  210.  
  211.     TITLE  :  How to Print in Windows
  212.  
  213.  
  214.  
  215.  
  216.   The coordinates used in TextOut are arbitrary.  Exactly lines can
  217.   be calculated from the values returned by GetTextMetrics as you
  218.   would for normal output to the screen.  See Chapter 4 of the
  219.   Windows Reference Guide of TPW for a complete description of the
  220.   TTextMetric type.  The tmHeight, tmAveCharWidth, and
  221.   tmMaxCharWidth fields will prove to be the most useful when
  222.   determining line lengths and the number of characters per page.
  223.   Use GetDeviceCaps to determine the maximum horizontal and
  224.   vertical resolutions of your printer when calculating these
  225.   values.
  226.  
  227.   Since device controls are used, printing graphics is a simple
  228.   extension of what is done to display graphics on screen.  Here's
  229.   a procedure that copies a bitmap to the printer using the
  230.   techniques that have been discussed so far.
  231.  
  232.   procedure HardCopy(HWindow: HWnd; BitMap: HBitMap);
  233.   var
  234.     DC, ScreenDC, MemDC: HDC;
  235.     BM: TBitMap;
  236.     OldBitMap: HBitMap;
  237.     Info, TInfo: PChar;
  238.     Driver, PrinterType, Port: PChar;
  239.   begin
  240.     GetMem(Info, 80);
  241.     GetProfileString('windows', 'device', ',,', Info, 80);
  242.     TInfo:=Info;
  243.     Driver:=GetInfo(Info);
  244.     PrinterType:=GetItem(Info);
  245.     Port:=GetItem(Info);
  246.  
  247.     DC:=CreateDC(PrinterType, Driver, Port, Nil);
  248.     Escape(DC, STARTDOC, 8, StrNew('HardCopy'), nil);
  249.     Escape(DC, NEWFRAME, 0, nil, nil);
  250.  
  251.     ScreenDC:=GetDC(HWindow);
  252.     MemDC:=CreateCompatibleDC(DC);
  253.     ReleaseDC(HWindow, ScreenDC);
  254.  
  255.     OldBitMap:=SelectObject(MemDC, BitMap);
  256.     GetObject(BitMap, sizeof(BM), @ BM);
  257.     BitBlt(DC, 0,0, BM.bmWidth, BM.bmHeight,
  258.        MemDC, 0, 0, SRCCOPY);
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272.   PRODUCT  :  Turbo Pascal                           NUMBER  :  607
  273.   VERSION  :  1.0
  274.        OS  :  Windows
  275.      DATE  :  May 13, 1992                            PAGE  :  5/10
  276.  
  277.     TITLE  :  How to Print in Windows
  278.  
  279.  
  280.  
  281.  
  282.     Escape(DC, NEWFRAME, 0, nil, nil);
  283.     Escape(DC, ENDDOC, 0, nil, nil);
  284.  
  285.     SelectObject(MemDC, OldBitMap);
  286.     DeleteDC(MemDC);
  287.     DeleteDC(DC);
  288.   end;
  289.  
  290.   For clarity, this routine does not perform error checking in the
  291.   manner of the previous example so use it with appropriate
  292.   caution.
  293.  
  294.   As with BitBlt, you may use any of the other GDI functions with a
  295.   DC associated with the printer.  The only difficulty that you may
  296.   run into in this regard is the capabilities of the printer
  297.   itself. To determine if a printer can handle bitmaps, use the
  298.   GetDeviceCaps function as follows.
  299.  
  300.               Value:=GetDeviceCaps(DC, RASTERCAPS);
  301.               Value:=Value and rc_BitBlt;
  302.  
  303.   Assuming, DC to be associate with a printer device and Value to
  304.   be declared as an integer, if the resulting contents of Value is
  305.   not zero then the device has the ability to display bitmaps.  See
  306.   Device Capabilities under Chapter 1 of TPW's Windows Reference
  307.   Guide for more on what GetDeviceCaps can do.
  308.  
  309.   Frequently, programs give user's the ability to change the
  310.   setting of the printer.  However, printers often have greatly
  311.   different capabilities and it is impossible to determine what
  312.   printers will be capable of in the future.  Therefore, no one
  313.   dialog is appropriate to change printer setting.  Because of
  314.   these facts, Windows requires the manufacturers of printers to
  315.   supply drivers and incorporate into these drivers a dialog used
  316.   to alter printer settings.
  317.  
  318.   There are two functions supported by the Windows API to call up
  319.   this dialog DeviceMode and ExtDeviceMode.  These functions do not
  320.   exist in the API but rather are loaded from the driver directly.
  321.   Before you can call on these functions you must obtain a driver
  322.   handle.  Here's how this would be done knowing what we know so
  323.   far.
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338.   PRODUCT  :  Turbo Pascal                           NUMBER  :  607
  339.   VERSION  :  1.0
  340.        OS  :  Windows
  341.      DATE  :  May 13, 1992                            PAGE  :  6/10
  342.  
  343.     TITLE  :  How to Print in Windows
  344.  
  345.  
  346.  
  347.  
  348.     GetMem(FullDriver,13);
  349.     GetProfileString('windows', 'device', ',,', Info, 80);
  350.     TInfo:=Info;
  351.     PrinterType:=GetItem(Info);
  352.     Driver:=GetItem(Info);
  353.     Port:=GetItem(Info);
  354.     StrLCat(StrCopy(FullDriver,Driver),'.DRV',12);
  355.     DriverHandle:=LoadLibrary(FullDriver);
  356.  
  357.   PrinterType, Driver, Port, Info, and TInfo you have seen above.
  358.   FullDriver is declared to be PChar and DriverHandle is a THandle.
  359.   FullDriver is necessary to provide the file extension to Driver
  360.   as the function LoadLibrary requires a complete file name.  All
  361.   printer drivers have the file extension .DRV.
  362.  
  363.   ExtDeviceMode is a more advanced form of DeviceMode.  It not only
  364.   provides the dialog to allow user's change settings but also
  365.   gives the means for the program to moniter and change the device
  366.   settings.  DeviceMode only provides the user dialog capability.
  367.   However, ExtDeviceMode was introduced in version 3.0 of Windows
  368.   and not all printer drivers provide a ExtDeviceMode function.
  369.   But, all printer driver provide a DeviceMode function.  So if
  370.   ExtDeviceMode is not present, DeviceMode will be.  The following
  371.   code is appropriate for displaying the printer's dialog.
  372.  
  373.         P:=GetProcAddress(DriverHandle, 'ExtDeviceMode');
  374.         if P<>nil then
  375.         begin
  376.           ExtDeviceMode:=TExtDeviceMode(P);
  377.           Size:=ExtDeviceMode(Window, DriverHandle,
  378.              OutModeRec^, PrinterType, Port,
  379.              InModeRec^, nil, 0);
  380.           GetMem(OutModeRec, Size);
  381.           GetMem(InModeRec, Size);
  382.           ExtDeviceMode(Window, DriverHandle,
  383.              OutModeRec^, PrinterType, Port,
  384.              InModeRec^, nil, dm_Prompt);
  385.           FreeMem(OutModeRec, Size);
  386.           FreeMem(InModeRec, Size);
  387.         end
  388.         else begin
  389.           P:=GetProcAddress(DriverHandle, 'DeviceMode');
  390.           DeviceMode:=TDeviceMode(P);
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403.  
  404.   PRODUCT  :  Turbo Pascal                           NUMBER  :  607
  405.   VERSION  :  1.0
  406.        OS  :  Windows
  407.      DATE  :  May 13, 1992                            PAGE  :  7/10
  408.  
  409.     TITLE  :  How to Print in Windows
  410.  
  411.  
  412.  
  413.  
  414.           DeviceMode(Window, DriverHandle, PrinterType, Port);
  415.         end;
  416.         FreeLibrary(DriverHandle);
  417.  
  418.   P is declared to be of type TFarProc; ExtDeviceMode is of type
  419.   TExtDeviceMode which is supplied by the WinTypes unit (the same
  420.   applies for DeviceMode and TDeviceMode).  Both OutModeRec and
  421.   InModeRec are declared to be of type PDevMode. These two pointers
  422.   control the input and output to ExtDeviceMode where required.
  423.  
  424.   Notice that if the results of GetProcAddress(DriverHandle,
  425.   'ExtDeviceHandle'); are nil then ExtDeviceHandle cannot be
  426.   provided by the printer.  In this case, the code proceeds to the
  427.   simple DeviceMode call.
  428.  
  429.   Before ExtDeviceMode can be called to prompt the user, it is a
  430.   good idea to call ExtDeviceMode with its mode parameter (the 8th
  431.   parameter) set to zero.  The result will be the amount of space
  432.   required for it input and output, TDevMode parameters.  This is
  433.   important as these records may not be the same size as the
  434.   TDevMode type.  After memory is allocated for these records, the
  435.   data fields of the input record may then be initialized (see
  436.   Chapter 4 of TPW's Windows Reference guide for more on TDevMode).
  437.  
  438.   Now ExtDeviceMode is called with the mode paramter set to
  439.   dm_Prompt which displays and activates the printer's dialog.
  440.   This constant can be combined with the other constants dm_Copy,
  441.   dm_Modify, and dm_Update with Turbo's bitwise OR operator. (See
  442.   Chapter 1 of TPW's Windows Reference Guide for information on
  443.   these dm_ Device mode selections).
  444.  
  445.   Another important feature for printing is the Abort Dialog.  An
  446.   Abort Dialog is a dialog displayed when printing is taking place
  447.   and gives the user of the program an opprotunity to halt printing
  448.   before it is finished.
  449.  
  450.   The first thing to do, is create a dialog suitable for the task.
  451.   Something like this .DLG file would serve (in a true DLG file all
  452.   data for statement would appear on a single line).  Though you
  453.   may prefer to use a resource toolkit of some sort to build your
  454.   dialog into a resource used by your program.
  455.  
  456.  
  457.  
  458.  
  459.  
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466.  
  467.  
  468.  
  469.  
  470.   PRODUCT  :  Turbo Pascal                           NUMBER  :  607
  471.   VERSION  :  1.0
  472.        OS  :  Windows
  473.      DATE  :  May 13, 1992                            PAGE  :  8/10
  474.  
  475.     TITLE  :  How to Print in Windows
  476.  
  477.  
  478.  
  479.  
  480.   ABORTBOX DIALOG DISCARDABLE LOADONCALL PURE MOVEABLE 10, 37, 187,
  481.     67
  482.   STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | 0x80L
  483.   CAPTION "Printing in Progress"
  484.   BEGIN
  485.     CONTROL "Escape" 100, "BUTTON", WS_CHILD | WS_VISIBLE |
  486.        WS_TABSTOP, 73, 37, 41, 16
  487.     CONTROL "Press Escape to Stop Printing" 102, "STATIC", WS_CHILD
  488.        | WS_VISIBLE, 44, 12, 99, 11
  489.   END
  490.  
  491.   Next, using the Object Windows Library, you would define an
  492.   object type to govern your Abort Dialog.  Its actuall definition
  493.   needs to be no more than something like the following.
  494.  
  495.   var
  496.     Abort: Boolean;
  497.     AbortWindow: HWindow;
  498.   type
  499.     PAbortDialog = ^TAbortDialog;
  500.     TAbortDialog = object(TDlgWindow)
  501.        procedure SetUpWindow; virtual;
  502.        procedure WMCommand(var Msg: TMessage);
  503.          virtual wm_First + wm_Command;
  504.     end;
  505.  
  506.   procedure TAbortDialog.SetUpWindow;
  507.   begin
  508.     Abort:=false;
  509.     SetFocus(HWindow);
  510.     AbortWindow:=HWindow;
  511.   end;
  512.  
  513.   procedure TAbortDialog.WMCommand(var Msg: TMessage);
  514.   {Will be entered whenever a button, return key or escape key is
  515.   pressed.}
  516.   begin
  517.     Abort:=true;
  518.   end;
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.  
  530.  
  531.  
  532.  
  533.  
  534.  
  535.  
  536.   PRODUCT  :  Turbo Pascal                           NUMBER  :  607
  537.   VERSION  :  1.0
  538.        OS  :  Windows
  539.      DATE  :  May 13, 1992                            PAGE  :  9/10
  540.  
  541.     TITLE  :  How to Print in Windows
  542.  
  543.  
  544.  
  545.  
  546.   As any button press, return key press, or escape key press will
  547.   abort printing only a WMCommand method is needed.  InitDialog is
  548.   necessary to set the focus to this dialog and to set the field
  549.   Abort.
  550.  
  551.   Abort is used by the dialog to determine if printing has been
  552.   aborted.  To prevent interrupting printing while the dialog is
  553.   displayed, a Call Back function is required to be installed.
  554.   Most such functions call PeekMessage which checks the application
  555.   queue for a message.  If there are no messages, it returns and
  556.   gives control to Windows.  Here's a simple example of such a
  557.   function.
  558.  
  559.   function AbortCallBack(DC: HDC; Code: Integer): Bool; export;
  560.   var
  561.     Msg: TMsg;
  562.   begin
  563.     While (not Abort) and PeekMessage(Msg, 0, 0, 0, pm_Remove) do
  564.     if not IsDialogMessage(AbortWindow, Msg) then
  565.     begin
  566.      TranslateMessage(Msg);
  567.      DispatchMessage(Msg);
  568.     end;
  569.     if Abort then AbortCallBack:=false else AbortCallBack:=true;
  570.   end;
  571.  
  572.   PeekMessage yields control to Windows when a message is not
  573.   available.  If a message is received and it doesn't belong to the
  574.   dialog, it is sent along using the customary TranslateMessage and
  575.   DispatchMessage functions.  After it checks to see if the user
  576.   has aborted and if so, AbortCallBack returns false.  Otherwise,
  577.   it simply returns true which indicates printing may continue.
  578.  
  579.   Now you have all that you need to install you Abort Dialog.
  580.   Before, your call to Escape for the STARTDOC,  the following code
  581.   should be executed (assuming that you have previously declared a
  582.   variable AbortDialog of type PAbortDialog and a variable called
  583.   AbortCallBackProc of type TFarProc to hold the address of the
  584.   callback function).
  585.  
  586.         AbortDialog:=New(PAbortDialog,
  587.           Init(Application^.MainWindow, 'ABORTBOX'));
  588.           AbortDialog:=PAbortDialog(Application^.
  589.  
  590.  
  591.  
  592.  
  593.  
  594.  
  595.  
  596.  
  597.  
  598.  
  599.  
  600.  
  601.  
  602.   PRODUCT  :  Turbo Pascal                           NUMBER  :  607
  603.   VERSION  :  1.0
  604.        OS  :  Windows
  605.      DATE  :  May 13, 1992                           PAGE  :  10/10
  606.  
  607.     TITLE  :  How to Print in Windows
  608.  
  609.  
  610.  
  611.  
  612.                                   MakeWindow(AbortDialog));
  613.           AbortCallBackProc:=MakeProcInstance(@ AbortCallBack,
  614.           HInstance);
  615.         Escape(DC, SETABORTPROC, 0, AbortCallBackProc, nil);
  616.  
  617.   Now you would call Escape with the appropriate STARTDOC,
  618.   NEWFRAME, and ENDDOC parameters as illustrated before. However,
  619.   it is vital to check for errors after a NEWFRAME escape call.
  620.   For printing actually occurs during the NEWFRAME.  If an error or
  621.   user abort occurs Escape will return a value less than zero.  If
  622.   this happens do not allow the ENDDOC escape call take place; for
  623.   the GDI automatically terminates the operation before returning
  624.   the error value.  Also, if an error other than a user abort
  625.   occurs, use AbortDialog^.CloseWindow to remove the dialog from
  626.   view.  If the user cancles the print operation, Windows removes
  627.   the dialog automatically.
  628.  
  629.  
  630.  
  631.  
  632.  
  633.  
  634.  
  635.  
  636.  
  637.  
  638.  
  639.  
  640.  
  641.  
  642.  
  643.  
  644.  
  645.  
  646.  
  647.  
  648.  
  649.  
  650.  
  651.  
  652.  
  653.  
  654.  
  655.  
  656.  
  657.  
  658.  
  659.  
  660.  
  661.